<template>
  <Form :layout="vertical" :model="formState" @finish="submit" ref="formRef" class="basefrom">
    <template v-for="(group, groupIndex) in option" :key="groupIndex">
      <!-- 分组标题 -->
      <div class="form-group-title">
        <h3>{{ group.groupTitle }}</h3>
      </div>
      <!-- 分组内的表单项 -->
      <Row :gutter="20">
        <template v-for="(item, index) in group.list" :key="index">
          <Col v-if="item && item.formName && visibleFields[item.formName] && item.type != 'no-show'"
            :span="24 / (!!group.num ? group.num : num)">
          <FormItem :label="item.label" :name="item.formName" :rules="item.rules">
            <component style="width: 100%;" :allowClear="true" :is="getComponent(item.type)" v-bind="{
              ...item,
              ...(componentPropsMap[item.type] ? componentPropsMap[item.type](item, dynamicOptions) : {}),
            }" v-model:value="formState[item.formName]"
              @change="(val: any, option: any) => onChange(val, item, option)" />
          </FormItem>
          </Col>
        </template>
        <!-- 提交按钮 -->
        <FormItem class="button-f" v-if="!noButton">
          <Button type="primary" html-type="submit" style="margin-left: auto">
            查询
          </Button>
        </FormItem>
      </Row>
    </template>

  </Form>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, defineExpose } from 'vue';
import { Input, Select, DatePicker, RangePicker, TreeSelect, Rate, Row, FormItem, Form, Col, Button } from 'ant-design-vue';
import dayjs from 'dayjs';
import type { VNode } from 'vue';
import type { FormInstance } from 'ant-design-vue';
import Baseupload from '../baseUpload/index.vue';

const toFetchOptions = ['select', 'tree-select'];
// 表单项类型定义
type baseInputType = {
  type: 'input' | 'rate';
  placeholder?: string;
  defaultValue?: any;
  disabled?: boolean;
};

type basedateType = {
  type: 'date' | 'range-picker';
  placeholder?: string;
  format: string;
  defaultValue?: string;
  disabled?: boolean;
  endDate?: string;
  startDate?: string;
};

type baseSelectType = {
  type: 'select';
  placeholder?: string;
  options: { label: string; value: string }[];
  defaultValue?: any;
  disabled?: boolean;
  loading?: boolean;
  fetchOptions?: (formValues: any) => Promise<{ label: string; value: string }[]>;
  linkField?: string;
};
type baseNoShowType = {
  type: 'no-show';
};
type baseRateType = {
  type: 'rate';
  allowHalf?: boolean;
  count?: number;
  defaultValue?: any;
  disabled?: boolean;
};
type baseUploadType = {
  type: 'upload';
  action: string; // 上传地址
  accept?: string; // 可接受的文件类型
  delUrl: string,

  maxFileCount?: number; // 最大上传文件数量
  customValidator?: (file: File) => boolean | string; // 自定义校验函数
  getFileGroupById?: (id: string) => Promise<{
    id: string,
    name: string,
    url: string
  }[]>; // 根据文件ID获取URL的接口
};
type baseTreeSelectType = {
  type: 'tree-select';
  placeholder?: string;
  options: { label: string; value: string }[];
  disabled?: boolean;
  loading?: boolean;
  fieldNames?: {
    children?: string;
    label?: string;
    value?: string;
  };
  fetchOptions?: (formValues: any) => Promise<{ label: string; value: string }[]>;
  linkField?: string;
};

// 表单项的配置类型，确保每个项有 formName 属性
export type baseFormOption = {
  formName: string;
  label: string | VNode;
  rules?: any;
  shouldDisplay?: (formValues: any) => boolean;
  defaultValue?: any;
  disabled?: boolean;
  loading?: boolean;
  onChangeHandler?: (val: any, formState: any, option: any) => void
} & (baseInputType | baseSelectType | baseUploadType | baseNoShowType | basedateType | baseRateType | baseTreeSelectType);

// 分组类型
export type baseFormGroupOption = {
  groupTitle: string;
  num?: number;
  list: baseFormOption[];
};

// 接收 props
const props = defineProps<{
  option: baseFormGroupOption[];
  num?: number;
  noButton?: boolean;
  initialValues?: Record<string, any>;
  vertical?: 'horizontal' | 'vertical' | 'inline'
}>();

const emit = defineEmits<{
  (e: 'submit', val: any): void;
}>();

// 默认 props
const num = props.num || 4;
const vertical = props?.vertical || 'vertical'

// 引用表单和动态选项
const formState = ref<Record<string, any>>({});
const dynamicOptions = ref<{ [key: string]: { label: string; value: string }[] }>({});
const visibleFields = ref<{ [key: string]: boolean }>({});

// 引用 Form 实例
const formRef = ref<FormInstance>();

// 使用 defineExpose 暴露 Form 方法
defineExpose({
  // 校验整个表单
  validate: () => (
    formRef.value?.validate().then(() => {
      submit()
    })
  ),

  // 重置所有表单字段
  resetFields: () => formRef.value?.resetFields(),

  // 校验指定字段
  validateFields: (names?: string[]) => (
    formRef.value?.validateFields(names).then(() => {
      submit()
    })
  ),

  // 滚动到指定字段
  scrollToField: (name: string) => formRef.value?.scrollToField(name),

  // 清除校验状态
  clearValidate: (names?: string[]) => formRef.value?.clearValidate(names),

});

// 动态获取组件
const componentPropsMap: any = {
  select: (item: any, dynamicOptions: Record<string, any>) => ({
    options: dynamicOptions[item.formName] || item.options, // 只传递 options
  }),
  'tree-select': (item: any, dynamicOptions: Record<string, any>) => ({
    treeData: dynamicOptions[item.formName] || item.options, // 只传递 treeData
  }),
};

// 动态获取组件类型
const getComponent = (type: string) => {
  switch (type) {
    case 'input':
      return Input;
    case 'select':
      return Select;
    case 'rate':
      return Rate;
    case 'date':
      return DatePicker;
    case 'range-picker':
      return RangePicker;
    case 'tree-select':
      return TreeSelect;
    case 'upload':
      return Baseupload;

    default:
      return Input;
  }
};

// 更新字段的显示状态
const updateVisibleFields = (allValues: any) => {
  const newVisibleFields: { [key: string]: boolean } = {};
  props.option.forEach((group) => {
    group.list.forEach((item) => {
      if (item.type == 'range-picker') {
        item.endDate && (newVisibleFields[item.endDate] = item.shouldDisplay ? item.shouldDisplay(allValues) : true);
        item.startDate && (newVisibleFields[item.startDate] = item.shouldDisplay ? item.shouldDisplay(allValues) : true);
      }
      newVisibleFields[item.formName] = item.shouldDisplay ? item.shouldDisplay(allValues) : true;
    });
  });
  visibleFields.value = newVisibleFields;
};

// 监听表单值变化
watch(
  formState,
  (newValues) => {
    props.option.forEach((group) => {
      group.list.forEach((item: any) => {
        if (toFetchOptions.includes(item.type) && item.linkField && newValues[item.linkField]) {
          const selectItem = item as baseFormOption & baseSelectType;
          if (selectItem.fetchOptions) {
            selectItem.fetchOptions(newValues).then((options) => {
              dynamicOptions.value = {
                ...dynamicOptions.value,
                [selectItem.formName]: options,
              };
            });
          }
        }
      });
    });

    updateVisibleFields(newValues);
  },
  { deep: true },
);

// 提交表单时触发的逻辑
const submit = () => {
  try {
    const filteredFormValues = Object.keys(formState.value).reduce((acc, key) => {
      if (visibleFields.value[key]) {
        const item = getFormItemByName(key)
        // TODO 这里可以写一个对象处理函数 现在少 多了 可以优化
        if (item?.type === 'date' || item?.type === 'range-picker') {
          // 格式化单一日期
          if (item?.type === 'date') {
            acc[key] = !!formState.value[key] ? (dayjs(formState.value[key]).format(item.format)) : undefined;
          }
          // 格式化日期范围
          if (item?.type === 'range-picker') {
            const [start, end] = formState.value[key] || [];
            if (item.startDate) acc[item.startDate] = !!start ? (dayjs(start).format(item.format)) : undefined;
            if (item.endDate) acc[item.endDate] = end ? (dayjs(end).format(item.format)) : undefined;
          }
        } else {
          acc[key] = formState.value[key];
        }
      }
      return acc;
    }, {} as Record<string, any>);
    emit('submit', filteredFormValues);
  } catch (err) {
    console.log(err)
  }

};
const getFormItemByName = (key: string) => {
  for (const group of props.option) {
    for (const item of group.list) {
      if (item.formName === key) {
        return item;
      }
    }
  }
  return null; // 找不到对应字段配置时
};

// 处理日期范围更新
const onChange = (val: any, item: baseFormOption, option: any) => {
  // 执行字段配置的 onChangeHandler 回调
  if (item.onChangeHandler) {
    item.onChangeHandler(val, formState.value, option);
  }
};

// 初始化表单状态
onMounted(() => {
  const initialValues: Record<string, any> = props.initialValues || {}; // 从父组件获取初始值

  props.option.forEach((group) => {
    group.list.forEach((item: any) => {
      // 使用 initialValues 中的值，若没有提供则使用 item.defaultValue
      if (item.type === 'date' && initialValues[item.formName]) {
        // 如果传入的值是字符串，转换成 dayjs 对象
        initialValues[item.formName] = initialValues[item.formName]
          ? dayjs(initialValues[item.formName]) // 如果有值，则转换为 dayjs
          : (item.defaultValue ? dayjs(item.defaultValue) : undefined); // 如果没有值，则使用 defaultValue 或 undefined
      }
      initialValues[item.formName] = item.defaultValue ?? initialValues[item.formName] ?? undefined;

      if (toFetchOptions.includes(item.type) && item.fetchOptions) {
        // 动态获取选项并更新动态选项
        item.fetchOptions(initialValues).then((options: any) => {
          dynamicOptions.value = {
            ...dynamicOptions.value,
            [item.formName]: options,
          };
        });
      }
    });
  });

  formState.value = initialValues; // 设置表单初始状态

  updateVisibleFields(initialValues); // 更新可见字段的显示状态
});
</script>

<style scoped lang="less">
.basefrom {
  &:deep(.ant-form-item) {
    margin-bottom: 12px;
  }

  &:deep(.css-dev-only-do-not-override-1dgrbo1.ant-input-affix-wrapper) {
    border: 1px solid #395c88;
  }

  &:deep(.css-dev-only-do-not-override-1dgrbo1.ant-picker) {
    border: 1px solid #395c88;
  }

  &:deep(.css-dev-only-do-not-override-1dgrbo1.ant-select:not(.ant-select-customize-input) .ant-select-selector) {
    border: 1px solid #395c88;
  }
}

.basefrom {
  .button-f {
    margin-left: auto !important;
  }
}

.form-group-title {
  font-weight: bold;
  font-size: 20px;
  color: #333;
}
</style>
